package com.xmlt.ui.editors.browsereditor;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.w3c.dom.Document;
import org.w3c.tidy.Tidy;

import com.xmlt.core.template.Template;
import com.xmlt.core.template.TemplateException;
import com.xmlt.core.template.TemplateManager;
import com.xmlt.core.template.TemplateParameter;
import com.xmlt.core.template.generation.GenerationTemplate;
import com.xmlt.ui.builder.BuilderPlugin;
import com.xmlt.ui.editors.EditorsPlugin;
import com.xmlt.ui.server.EditorContext;
import com.xmlt.ui.server.EmbeddedServer;

public class GenerationTemplateEditor extends BrowserEditor  {

	private TemplateManager manager;
	private GenerationTemplate genTemplate;

	public GenerationTemplateEditor() {
	}
	
	@Override
	protected String getURL() {
		return EmbeddedServer.getRootUrl() + "generationtemplate.jsp?"
				+ EditorContext.EDITOR_CONTEXT_ID_PARAM + "=" + getEditorContext().getContextId();
	}
	
	@Override
	public Document getEditedDocument() {
		return genTemplate.getDocument();
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
	throws PartInitException {
		super.init(site, input);
		
		IFile file = (IFile) input.getAdapter(IFile.class);
		manager = BuilderPlugin.getTemplateManager(file.getProject());
		String ref = file.getProjectRelativePath().toString();
		try {
			genTemplate = manager.findGenerationTemplate(ref);
		} catch (TemplateException e) {
			IStatus eStatus = new Status(IStatus.ERROR, EditorsPlugin.PLUGIN_ID, e.getMessage(), e);
			throw new PartInitException(eStatus);
		}
		getEditorContext().setWrappedObject(genTemplate);
	}

	/**
	 * Saves the editor's document.
	 */
	public void doSave(IProgressMonitor monitor) {
		try {
			String browserContents = getBrowser().getText();
			Tidy tidy = new Tidy();
			Document n = tidy.parseDOM(
					new ByteArrayInputStream(browserContents.getBytes()),
					null);
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer t = tf.newTransformer(new StreamSource(EditorsPlugin
					.getResourceFile("site/xml/GenerationTemplateSave.xsl")));
			t.setOutputProperty(OutputKeys.INDENT, "yes");
			StringWriter sw = new StringWriter();
			t.transform(new DOMSource(n), new StreamResult(sw));
			//System.out.println(sw.toString());
			
			IEditorInput input = getEditorInput();
			IFile f = (IFile) input.getAdapter(IFile.class);
			f.setContents(new ByteArrayInputStream(sw.toString().getBytes()),
					IFile.REPLACE, monitor);
			f.refreshLocal(IResource.DEPTH_ONE, monitor);
			init(getEditorSite(), input);
			
			setDirty(false);
			firePropertyChange(PROP_DIRTY);
		} catch (Exception e) {
			MessageDialog.openError(getEditorSite().getShell(), "Error while saving file", e.getMessage());
		}
	}

	@Override
	protected void refresh() {
	}

	@Override
	public String getContent() {
		return "";
	}
	
	@Override
	public void setContent(String c) {
	}

	@Override
	protected void addCustomfunctions() {
		new TreeContentGenerator();
		new TemplatesSelectGenerator();
	}
	
	private class TreeContentGenerator extends MessengerFunction {

		public TreeContentGenerator() {
			super("getTreeContent");
		}
		
		@Override
		public Object function(Object[] arguments) {
			try {
				String templateRef = String.valueOf(arguments[0]);
				if (templateRef == null)
					templateRef = "";
				String str = "<ul id=\"tree\" class=\"treeview-famfamfam\">";
				str += "<li><b>Special controls</b><ul>";
				str += "<li><span id='expression_draggable' class='expression draggable'><b>expression</b></span></li>";
				str += "<li><span id='condition_draggable' class='condition draggable'><b>condition</b></span></li>";
				str += "</ul></li>";
				str += "<li><b>Elements</b><ul>";
				// add template params here
				if (!templateRef.equals("")) {
					Template template = manager.findTemplate(templateRef);
					if (template != null) {
						List<Template> usedTemplates = new ArrayList<Template>();
						usedTemplates.add(template);
						List<TemplateParameter> params = template.getParameters();
						for (TemplateParameter p: params) {
							try {
								str += getParamString(p, null, usedTemplates);
							} catch (TemplateException te) {
								continue;
							}
						}
					} else {
						str += "no linked template!";
					}
				}
				str += "</ul></li></ul>";
				return str;
			} catch (Exception e) {
				return e.getMessage();
			}
		}
		
		private String getParamString(TemplateParameter p, String prefix, List<Template> usedTemplates) throws TemplateException {
			String str = "<li>";
			String id = prefix == null ? p.getName() : prefix + "."
					+ p.getName();
			if (p.isLink() || p.isReference()) {
				Template linkedTemplate = null;
				try {
					linkedTemplate = p.getTemplate();
				} catch (TemplateException te) {}
				if (linkedTemplate == null) {
					str += "<span><b>invalid reference</b></span>";
				} else {
					List<TemplateParameter> children = linkedTemplate.getParameters();
					str += "<span id='element_" + id
							+ "' class='element draggable' value='" + id + "'><b>"
							+ p.getName() + "</b></span>";
					if (p.isMultiple()) {
						str += "  <span id='loop_" + id
								+ "' class='loop draggable' value='" + id
								+ "'>loop</span>";
					}
					str += "<ul>";
					if (!usedTemplates.contains(linkedTemplate)) {
						List<Template> usedTemplatesCopy = new ArrayList<Template>();
						usedTemplatesCopy.addAll(usedTemplates);
						usedTemplatesCopy.add(linkedTemplate);
						for (TemplateParameter cp : children) {
							str += getParamString(cp, id, usedTemplatesCopy);
						}
					} else {
						str += "<span><b>Detected circular reference.<br/> Children cannot be loaded.</b></span>";
					}
					str += "</ul>";
				}
			} else if (p.isValue()) {
				str += "<span id='element_" + id
						+ "' class='element draggable' value='" + id + "'>"
						+ p.getName() + "</span>";
				if (p.isMultiple()) {
					str += "  <span id='loop_" + id
							+ "' class='loop draggable' value='" + id
							+ "'>loop</span>";
				}
			}
			str += "</li>";
			return str;
		}
		
	}
	
	private class TemplatesSelectGenerator extends MessengerFunction {

		public TemplatesSelectGenerator() {
			super("getTemplatesSelectString");
		}
		
		@Override
		public Object function(Object[] arguments) {
			String templateRef = String.valueOf(arguments[0]);
			if (templateRef == null)
				templateRef = "";
			String s = "<select id='templates_select' onchange='setTemplateRef(this);'>";
			s += "<option value='' " + (templateRef.equals("")? "selected": "") + ">Select one</option>";
			Map<String, Template> templates = manager.getAllTemplates();
			for (String ref : templates.keySet()) {
				s += "<option value='" + ref + "' " + (templateRef.equals(ref)? "selected": "") + ">" + ref + "</option>";
			}
			s += "</select>";
			return s;
		}
	}

}
